package com.dianmi.seckill.service.impl;

import com.dianmi.seckill.common.utils.JsonUtil;
import com.dianmi.seckill.config.PayStatusEnum;
import com.dianmi.seckill.config.RocketMQConstant;
import com.dianmi.seckill.dao.OrderDao;
import com.dianmi.seckill.dao.ProductDao;
import com.dianmi.seckill.entity.OrderInfo;
import com.dianmi.seckill.entity.SubstractStockInfo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.rocketmq.client.producer.SendCallback;
import org.apache.rocketmq.client.producer.SendResult;
import org.apache.rocketmq.common.message.Message;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallback;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.nio.charset.StandardCharsets;

@Slf4j
@Service
public class OrderServiceImpl {

    private static final String TRANS_SUBSTRACT_FAILED_MSG = "transcation substract failed, productId: %s, userId: %s";

    private static final String PAY_DELAY_FAILED_MSG = "pay delay msg failed, productId: %s, userId: %s";

    private static final String USER_ORDER_KEY = "user_order_key:%s:%s";

    @Resource
    private OrderDao orderDao;

    @Resource
    private ProductDao productDao;

    @Autowired
    private TransactionTemplate transactionTemplate;

    @Autowired
    private RocketMQTemplate rocketMQTemplate;

    @Autowired
    private SeckillServiceImpl seckillService;

    @Autowired
    private ProductServiceImpl productService;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    public boolean substractStock(SubstractStockInfo substractStockInfo) {
        boolean isSucc = false;
        Long orderId;
        try {
            orderId = transactionTemplate.execute(new TransactionCallback<Long>() {
                @Override
                public Long doInTransaction(TransactionStatus status) {
                    int num = productDao.substractStock(substractStockInfo.getId(), 1);
                    if (num > 0) {
                        OrderInfo orderInfo = new OrderInfo();
                        orderInfo.setProductId(substractStockInfo.getId());
                        orderInfo.setUserId(substractStockInfo.getUserId());
                        orderInfo.setTotalPrice(substractStockInfo.getPrice());
                        orderInfo.setPayStatus(PayStatusEnum.WAIT_TO_PAY.getPayStatus());
                        orderDao.insert(orderInfo);
                        return orderInfo.getId();
                    }
                    return null;
                }
            });
            isSucc = orderId != null;
            if (isSucc) {
                Message message = new Message(RocketMQConstant.PAY_PRODUCT_TOPIC, JsonUtil.toJson(substractStockInfo).getBytes(StandardCharsets.UTF_8));
                //rocketmq时间间隔为：1s、 5s、 10s、 30s、 1m、 2m、 3m、 4m、 5m、 6m、 7m、 8m、 9m、 10m、 20m、 30m、 1h、 2h
                message.setDelayTimeLevel(3);

                rocketMQTemplate.getProducer().send(message, new SendCallback() {
                    @Override
                    public void onSuccess(SendResult sendResult) {
                        log.info("pay delay message, productId: {}, userId: {}", substractStockInfo.getId(), substractStockInfo.getUserId());
                        seckillService.userJoinFlag(substractStockInfo.getId(), substractStockInfo.getUserId());
                    }

                    @Override
                    public void onException(Throwable throwable) {
                        log.error(String.format(PAY_DELAY_FAILED_MSG, substractStockInfo.getId(), substractStockInfo.getUserId()), throwable);
                    }
                });
                /*rocketMQTemplate.asyncSend(RocketMQConstant.PAY_PRODUCT_TOPIC, message, new SendCallback() {
                    @Override
                    public void onSuccess(SendResult sendResult) {
                        log.info("pay delay message, productId: {}, userId: {}", substractStockInfo.getId(), substractStockInfo.getUserId());
                        seckillService.userJoinFlag(substractStockInfo.getId(), substractStockInfo.getUserId());
                    }

                    @Override
                    public void onException(Throwable throwable) {
                        log.error(String.format(PAY_DELAY_FAILED_MSG, substractStockInfo.getId(), substractStockInfo.getUserId()), throwable);
                    }
                });*/
            }
        } catch (Exception e) {
            isSucc = false;
            productService.restore(substractStockInfo.getId());
            log.error(String.format(TRANS_SUBSTRACT_FAILED_MSG, substractStockInfo.getId(), substractStockInfo.getUserId()), e);
        }
        return isSucc;
    }

    public OrderInfo queryOrder(Long productId, Long userId) {
        String orderJson = stringRedisTemplate.opsForValue().get(String.format(USER_ORDER_KEY, productId, userId));
        if (StringUtils.isNoneBlank(orderJson)) {
            return JsonUtil.parseJson(orderJson, OrderInfo.class);
        }
        OrderInfo order = orderDao.selectUserOrder(productId, userId);
        if (order != null) {
            stringRedisTemplate.opsForValue().set(String.format(USER_ORDER_KEY, productId, userId), JsonUtil.toJson(order));
            return order;
        }
        return null;
    }
}
